<script setup lang="ts">
import { onBeforeUnmount, onMounted, onUnmounted, reactive, ref } from 'vue';
import mammoth from 'mammoth';
import _ from 'underscore';
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router';
import * as htmlDocx from 'html-docx-js-typescript';
import { saveAs } from 'file-saver';
import { useDialog } from 'naive-ui';
import {errorMessage, escapeHTMLManually, getImageInfoFromBase64, successMessage} from '@/utils/utils';
import { useRouterPush } from '@/hooks/common/router';
import AddImg from '@/assets/imgs/icon-catalog-add.png';
import EditImg from '@/assets/imgs/icon-catalog-edit.png';
import WriteImg from '@/assets/imgs/icon-catalog-write.png';
import DeleteImg from '@/assets/imgs/icon-catalog-delete.png';
import CompleteImg from '@/assets/imgs/icon-complete.png';
import IncompleteImg from '@/assets/imgs/icon-incomplete.png';
import { useBoolean } from '~/packages/hooks';
import DocumentName from '@/views/document/detail/modules/document-name.vue';
import { generateContent, getDocumentLabelAction, updateWriteAction } from '@/service/api';
import { localStg } from '@/utils/storage';
import { USER_INFO } from '@/utils/const';

const { bool: showDocNameModal, setTrue: openDocNameModal } = useBoolean();

const { routerBack, routerPushByKey } = useRouterPush();
const router = useRouter();
const { query } = useRoute();

const showLoading = ref<boolean>(true);
const loadingDes = ref<string>('文档较大，正在努力处理中，请稍后...');

// 生成类型 0：正常生成；1：编辑
const generateType = ref<number>(0);
const contentHtml = ref<string>('');
const docContentHtml = ref<string>('');
const imgList = ref<any[]>([]);
const IMAGE_TAG: string = 'IMAGE_TAG';
const contentTextLength = ref<number>(0);

/**
 * taskId: taskInfo.id, fileName: formData.value.projectName, infoPath: data[0].filePath, zhaoBiaoPath:
 * docFilePath.value, catalogPath: simpleInfo.doc_path
 */
const taskId = ref<any>(0); // 任务Id
const infoPath = ref<any>(''); // 模板信息文档地址
const zhaoBiaoPath = ref<any>(''); // 招标文件地址（新建上传的）
const catalogPath = ref<any>(''); // 生成的目录文件地址
const doneFilePath = ref<any>(''); // 生成的标书文件地址
const fileName = ref<any>('');

onMounted(() => {
  console.log('query: ', query);
  // generateType.value = Number.parseInt(query.generateType as string, 10);
  // taskId.value = Number.parseInt(query.taskId as string, 10);
  // fileName.value = query.fileName;
  // if (generateType.value === 0) {
  //   infoPath.value = query.infoPath;
  //   zhaoBiaoPath.value = query.zhaoBiaoPath;
  //   catalogPath.value = query.catalogPath;
  //   doneFilePath.value = query.doneFilePath;
  // }
});

// 编辑器配置
const editorConfig: object = reactive({
  serverUrl: '',
  UEDITOR_HOME_URL: '/modules/bidWriting/UEditorPlus/',
  UEDITOR_CORS_URL: '/modules/bidWriting/UEditorPlus/',
  toolbars: [['source', 'retouch']],
  autoFloatEnabled: false,
  readonly: true,
  autoSaveEnable: false, // 禁用自动保存
  elementPathEnabled: false, // 禁用元素路径
  initialFrameHeight: '700',
  autoHeightEnabled: false, // 禁止编辑器自动长高
  maximumWords: 1000000
});

// 引入的js文件，这里是一定要写的。
const editorDependencies: string[] = reactive(['ueditor.config.js', 'ueditor.all.js', 'lang/zh-cn/zh-cn.js']);

const ueditor = ref<any | null>(null);

function readyHandle(editor: any) {
  ueditor.value = editor;

  // 监听内容变化
  ueditor.value.addListener('updateSections', getCatalogHandle);

  // 监听内容变化
  editor.addListener('contentchange', () => {
    // console.log('编辑器内容发生改变');
    contentTextLength.value = ueditor.value.getContentLength(true);
  });

  // 润色
  ueditor.value.commands.retouch = {
    execCommand(cmd: string, format: any) {
      contentGenerate(cmd);
    }
  };

  // const iframeEle = document.getElementsByTagName('iframe');
  // console.log('iframeEle: ', iframeEle);
  // const iframeBody: any = iframeEle[0];
  // iframeBody.className = 'save_doc';
  // console.log('iframeBody: ', iframeBody);

  // 编辑器初始化成功后再获取文档内容
  getHtmlByDocument('/profile/biaoshu/批量化试验数字管控系统-招标文件.docx');

  // if (generateType.value === 0) {
  //   // 编辑器初始化成功后再获取文档内容
  //   getHtmlByDocument(catalogPath.value);
  // } else {
  //   getTaskInfoHandle();
  // }
}

// 改写/扩写/缩写/润色内容生成
function contentGenerate(type: string) {
  // 获取选中的内容
  let selectionText: string = '';
  // 获取当前选中的文本
  const selection = ueditor.value.selection.getRange();
  selection.select();
  selectionText = ueditor.value.selection.getText();

  console.log('selectionText: ', selectionText);
}

const catalogMap: any = {};

// 解析目录树
function analyzeDirectoryTree(section: any) {
  let liItem;
  let completeImg;
  let incompleteImg;
  let titleItem;
  let sectionItem;
  let itemContent;
  let editImg;
  let handleItem;
  let writeImg;
  let deleteImg;
  let addImg;
  let ulList;
  let child;
  let childList;
  if (section.children.length) {
    ulList = document.createElement('ul');
    for (let i: number = 0; i < section.children.length; i++) {
      child = section.children[i];
      // console.log("child.startAddress: ", child)
      // 设置目录节点内容标签(去除前后的空格)
      const title = child.title.trim();
      if (title.length === 0) continue;
      // 已完成
      completeImg = document.createElement('img');
      completeImg.src = CompleteImg;
      completeImg.className = 'statusIcon';
      // 未编写
      incompleteImg = document.createElement('img');
      incompleteImg.src = IncompleteImg;
      incompleteImg.className = 'statusIcon';

      // 目录标题
      sectionItem = document.createElement('span');
      sectionItem.className = 'itemTitle';
      sectionItem.textContent = title;
      editImg = document.createElement('img');
      editImg.src = EditImg;
      editImg.className = 'editIcon';
      titleItem = document.createElement('div');
      titleItem.className = 'titleItem';
      // titleItem.append(completeImg);
      titleItem.append(sectionItem);
      // titleItem.append(editImg);

      writeImg = document.createElement('img');
      writeImg.src = WriteImg;
      writeImg.className = 'writeIcon';
      addImg = document.createElement('img');
      addImg.src = AddImg;
      addImg.className = 'addIcon';
      deleteImg = document.createElement('img');
      deleteImg.src = DeleteImg;
      deleteImg.className = 'deleteIcon';
      handleItem = document.createElement('div');
      handleItem.className = 'handleItem';
      handleItem.append(writeImg);
      handleItem.append(addImg);
      handleItem.append(deleteImg);

      itemContent = document.createElement('div');
      itemContent.className = 'sectionItem';
      itemContent.append(titleItem);
      // itemContent.append(handleItem);
      itemContent.setAttribute('data-address', child.startAddress.join(','));

      catalogMap[child.startAddress.join(',')] = child;
      // 设置目录节点容器标签
      liItem = document.createElement('li');
      liItem.setAttribute('type', child.tag);
      liItem.append(itemContent);
      // 继续遍历子节点
      if (liItem.children.length) {
        childList = analyzeDirectoryTree(child);
        childList && liItem.append(childList);
      }
      ulList.append(liItem);
    }
  }
  return ulList;
}

const dialog = useDialog();

interface paragraphType {
  title?: string;
  address?: number;
}
const selectParagraph = ref<paragraphType>({});

// 获取文档目录树
function getCatalogHandle() {
  const catalogTree: any = ueditor.value.execCommand('getsections');
  contentTextLength.value = ueditor.value.getContentLength(true);

  // console.log('目录树：', catalogTree);
  // console.log('目录树：', analyzeDirectoryTree(catalogTree));
  // console.log('目录树catalogMap：', catalogMap);
  const directoryTree = analyzeDirectoryTree(catalogTree);
  // console.log('directoryTree: ', directoryTree);

  if (!directoryTree) return;

  // 更新目录树
  const catalogEle = document.getElementById('catalog_box')!;
  catalogEle.innerHTML = directoryTree?.outerHTML;

  /** 选中章节监听sectionItem的点击事件会让下面其他点击事件优先跳转到对应内容再触发 监听itemTitle的点击事件只会点击章节标题才会跳转 */
  // 选中章节
  const sectionItemEle = document.getElementsByClassName('itemTitle');
  for (let i: number = 0; i < sectionItemEle.length; i++) {
    sectionItemEle[i].addEventListener('click', (e: any) => {
      // console.log("e: ", e, e.target);
      const address = e.target.parentElement.parentElement.getAttribute('data-address');
      ueditor.value.execCommand('selectsection', catalogMap[address], true);
      // 清除选区
      ueditor.value.selection.clearRange();
    });
  }
  // console.log('sectionItemEle:', sectionItemEle);
}

const userInfo: Api.Auth.UserInfo = localStg.get(USER_INFO)!;

// 保存内容到服务器
async function saveContentToService(status: number) {
  const htmlContentStr: string = ueditor.value.getContent();
  // console.log("htmlContentStr: ", htmlContentStr);

  // htmlContentStr = htmlContentStr.replace(/<img /g, '<img width="650" height="650"');

  // 设置表格边框
  const htmlContent = htmlContentStr.replaceAll(/<table/g, `<table border-collapse="collapse" border="1" `);

  // const saveParams: any = {
  //   contentList: sliceStringByLength(`<div>${htmlContent}</div>`, 40000)
  // };
  //
  // const { data, error } = await htmlToDocAction(saveParams);
  // // console.log('data: ', data);
  // if (!error) {
  //
  // }
  const params: any = {
    id: taskId.value, // 必传
    title: fileName.value, // 标题
    type: 1, // 文件类型(1.标书 )
    materialType: 1, // 素材类型(1.标书)
    industryType: 1, // 行业类型(1.软件类 2.服务类 3.货物类 4.工程类 20.其他)
    status, // 0、生成中 1、已完成
    originalFilePath: catalogPath.value, // 标书目录文档地址
    filePath: htmlContent, // 生成的标书文档地址
    more1: infoPath.value, // 标书基本信息文档地址
    more2: zhaoBiaoPath.value // 上传的招标文档地址
  };
  await updateWriteAction(params);
}

// 根据文档获取html内容
function getHtmlByDocument(filePath: string) {
  const { VITE_OTHER_SERVICE_BASE_URL } = import.meta.env;
  const otherUrl = JSON.parse(VITE_OTHER_SERVICE_BASE_URL);
  const docPath: string = otherUrl.fileUrl + filePath;
  loadingDes.value = '文档较大，正在努力处理中，请稍后...';
  showLoading.value = true;
  fetch(docPath, { cache: 'no-cache' })
    .then(response => response.blob())
    .then(blobData => {
      let file: File | null = new File([blobData], `${fileName.value}.docx`, {
        type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        lastModified: Date.now()
      });

      analysisWord(file).then(html => {
        // console.log("html: ", html);
        for (let i: number = 0; i < imgList.value.length; i++) {
          // if (i === 0) {
          //   const imgRegex = /<img[^>]*?src="data:image\/[^;]+;base64,([^"]+)"/;
          //   let match;
          //   const base64Encodings = [];
          //
          //   while ((match = imgRegex.exec(imgList.value[i]))) {
          //     base64Encodings.push(match[1]); // 提取base64编码
          //   }
          //
          //   console.log("base64Encodings: ", base64Encodings);
          // }
          // docContentHtml.value = docContentHtml.value.replace(IMAGE_TAG, imgList.value[i]);
        }
        docContentHtml.value = docContentHtml.value.replace(/style=""/g, '');
        // console.log("docContentHtml.value: ", docContentHtml.value);
        // 插入文本
        ueditor.value.setContent(docContentHtml.value);
        // ueditor.value.execCommand('inserthtml', docContentHtml.value);
        // 设置内容光标到内容最前面
        ueditor.value.focus();
        getCatalogHandle();
        showLoading.value = false;
        // nextTick(() => {
        //   saveContentToService(1);
        // });
      });

      // 文件信息置空
      file = null;
    })
    .catch(error => {
      console.error('发生错误：', error);
      errorMessage('获取文档失败');
      showLoading.value = false;
    });
}

// 解析word文件，将word转为html
function analysisWord(file: any) {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = evt => {
      console.log('evt：', evt);
      // 当文件读取完毕后
      // p标签首行没有缩进
      const options = {
        transformDocument: transformElement,
        styleMap: ["p[style-name='Section Title'] => h1:fresh", "p[style-name='Subsection Title'] => h2:fresh"]
      };

      // 调用mammoth组件的方法进行解析文件
      mammoth
        .convertToHtml({ arrayBuffer: evt.target!.result }, options)
        .then(async resultObject => {
          // console.log("resultObject: ", resultObject);
          // resultObject.value = imgTagAddStyle(resultObject.value);
          const imgSrcReg = /<img[^>]+src=[\\'|\\"]?([^(?"|?'|?>)]+)[\\'|\\"]?[^>]*>/gim;
          const imgSrcList = resultObject.value.match(imgSrcReg);
          for (let i: number = 0; i < imgSrcList?.length; i++) {
            const imgSrc: string = imgSrcList[i].match(/src="(.+?)"/)[1];

            // console.log('imgSrc: ', imgSrc);
            const info = await getImageInfoFromBase64(imgSrc);
            if (info) {
              imgSrcList[i] =
                `${imgSrcList[i].substring(0, imgSrcList[i].length - 2)}width="${info.width}" height="${info.height}" ${imgSrcList[i].substring(imgSrcList[i].length - 2)}`;
            } else {
              imgSrcList[i] =
                `${imgSrcList[i].substring(0, imgSrcList[i].length - 2)}width="90%" height="auto" ${imgSrcList[i].substring(imgSrcList[i].length - 2)}`;
            }

            // 使用DOM解析器创建一个DOM元素
            // const domParser = new DOMParser();
            // const contentDom = domParser.parseFromString(imgSrcList[i], 'text/html');
            // const imgNode = contentDom.body.childNodes;
            //
            // console.log('imgNode: ', imgNode);
          }

          if (imgSrcList) {
            imgList.value = imgSrcList;
          }

          // console.log('imgList: ', imgList.value);
          resolve(resultObject.value); // 将处理好的html数据返回
          reader.abort(); // 关闭读取
        })
        .catch(err => {
          console.log('err: ', err);
          reader.abort(); // 关闭读取
        });
    };
    reader.readAsArrayBuffer(file);
    // 启动读取指定的 Blob 或 File 内容：https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsArrayBuffer
  });
}

// 给html标签中的img标签设置样式
function imgTagAddStyle(htmlstr: string) {
  // 正则匹配所有img标签
  // var regex0 = new RegExp("(i?)(\<img)([^\>]+\>)","gmi");
  // 正则匹配不含style="" 或 style='' 的img标签
  const regex1 = /(i?)(<img)(?!(.*?style=['"](.*)['"])[^>]+>)/gim;
  // 给不含style="" 或 style='' 的img标签加上style=""
  htmlstr = htmlstr.replace(regex1, '$2 style=""$3');
  // console.log(`增加style=""后的html字符串：${htmlstr}`);
  // 正则匹配含有style的img标签
  const regex2 = /(i?)(<img.*?style=['"])([^>]+>)/gim;
  // 在img标签的style里面增加css样式(这里增加的样式：display:block;max-width:100%;height:auto;border:5px solid red;)
  htmlstr = htmlstr.replace(regex2, '$2width:90%;height:auto;text-align:center;$3');
  // console.log(`在img标签的style里面增加样式后的html字符串：${htmlstr}`);
  return htmlstr;
}

// 获取图片尺寸
function base64DataURLToImageData(url: string) {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.src = url;
    image.onload = () => {
      resolve({
        width: image.width, // 图片原宽度
        height: image.height, // 图片原高度
        scale: image.height / image.width, // 图片高度与宽度之比
        scaleWidth: 300, // 设置的缩放后的宽度为300，可根据实际需求调整
        scaleHeight: (image.height / image.width) * 300, // 计算缩放后的高度
        src: url // 图片url
      });
    };
    image.onerror = () => {
      reject(new Error('error'));
    };
  });
}

/**
 * transformElement 和 transformParagraph 是用于将文档转换为HTML的。 用于文档转换的API是不稳定的，并且可能在任何版本之间发生变化。
 * 如果你依赖这种行为，你应该固定到mammath.js的特定版本，并在更新前仔细测试。
 */
// 元素重新定义
function transformElement(element: any) {
  if (element.children) {
    const children: any = _.map(element.children, transformElement);
    element = { ...element, children };
  }

  if (element.type === 'paragraph') {
    element = transformParagraph(element);
  }

  if (element.type === 'document') {
    // docParagraphList.value = element.children;
    console.log('docParagraphList.value: ', element.children);
    htmlFormat(element.children);
  }

  return element;
}

// 段落内容重新定义
function transformParagraph(element: any) {
  if (element.alignment === 'center' && !element.styleId) {
    return { ...element, styleId: 'Heading2' };
  }
  return element;
}

// 根据文档解析API进行HTML内容拼接封装
function htmlFormat(docParagraphList: any[]) {
  let docHtmlStr: string = '';
  for (let i: number = 0; i < docParagraphList.length; i++) {
    const paragraphObj: any = docParagraphList[i];
    if (paragraphObj.type === 'paragraph') {
      // 普通段落内容（包括文字和图片）
      let paragraphStr: string = '';
      let alignmentStr: string = '';
      if (paragraphObj.alignment) {
        alignmentStr = `text-align: ${paragraphObj.alignment}; line-height: 150%; align-items: baseline;`;
      } else {
        alignmentStr = 'text-align: left; line-height: 150%; align-items: baseline;';
      }

      for (let j: number = 0; j < paragraphObj.children.length; j++) {
        if (paragraphObj.indent && paragraphObj.indent.firstLine) {
          alignmentStr += 'text-indent: 2em;';
        }
        const formatContent = paragraphHtmlFormat(paragraphObj.children[j]);
        if (formatContent === IMAGE_TAG) {
          alignmentStr = 'display: block; text-align: center;';
        }
        paragraphStr += formatContent;
      }
      if (paragraphObj.styleId === 'Heading1' || paragraphObj.styleName === 'heading 1') {
        docHtmlStr += `<h1 style="${alignmentStr}">${paragraphStr}</h1>`;
      } else if (paragraphObj.styleId === 'Heading2' || paragraphObj.styleName === 'heading 2') {
        docHtmlStr += `<h2 style="${alignmentStr}">${paragraphStr}</h2>`;
      } else if (paragraphObj.styleId === 'Heading3' || paragraphObj.styleName === 'heading 3') {
        docHtmlStr += `<h3 style="${alignmentStr}">${paragraphStr}</h3>`;
      } else if (paragraphObj.styleId === 'Heading4' || paragraphObj.styleName === 'heading 4') {
        docHtmlStr += `<h4 style="${alignmentStr}">${paragraphStr}</h4>`;
      } else if (paragraphObj.styleId === 'Heading5' || paragraphObj.styleName === 'heading 5') {
        docHtmlStr += `<h5 style="${alignmentStr}">${paragraphStr}</h5>`;
      } else if (paragraphObj.styleId === 'Heading6' || paragraphObj.styleName === 'heading 6') {
        docHtmlStr += `<h6 style="${alignmentStr}">${paragraphStr}</h6>`;
      } else {
        docHtmlStr += `<p style="${alignmentStr}">${paragraphStr}</p>`;
      }
    } else if (paragraphObj.type === 'table') {
      // 表格内容处理
      const tableObj: any = docParagraphList[i];
      docHtmlStr += tableHtmlFormat(tableObj);
    }
  }
  docContentHtml.value = `<div style="margin: 72pt;">${docHtmlStr}</div>`;
}

// 段落内容格式化
function paragraphHtmlFormat(paragraphObj: any) {
  let contentStr: string = '';

  // console.log("paragraphObj: ", paragraphObj);

  if (!paragraphObj.children) {
    return '<span></span>';
  }

  if (paragraphObj.children.length === 0) {
    return '<br/>';
  }

  for (let i: number = 0; i < paragraphObj.children.length; i++) {
    if (paragraphObj.children[i].type === 'text') {
      let textStr: string = paragraphObj.children[i].value;
      // 如果有html字符串，将其解析为html字符串，就可以正常展示
      textStr = escapeHTMLManually(textStr);

      let styleStr: string = `line-height: 150%;`;
      if (paragraphObj.font) {
        styleStr += `font-family: ${paragraphObj.font};`;
      }
      if (paragraphObj.fontSize) {
        styleStr += `font-size: ${paragraphObj.fontSize}pt;`;
      }
      // 是否有下划线
      if (paragraphObj.isUnderline) {
        styleStr += 'text-decoration: underline;';
      }
      // 是否有删除线
      if (paragraphObj.isStrikethrough) {
        styleStr += 'text-decoration: line-through;';
      }
      // if (paragraphObj.verticalAlignment) {
      //   styleStr += `display: block; align-items: ${paragraphObj.verticalAlignment};`;
      // }
      // 是否加粗(使用 strong 标签加粗内容)
      if (paragraphObj.isBold) {
        styleStr += 'font-weight: bold;';
      }
      contentStr += `<span style="${styleStr}">${textStr}</span>`;
    } else if (paragraphObj.children[i].type === 'break') {
      // 换行
      contentStr += '<br/>';
    } else if (paragraphObj.children[i].type === 'image') {
      // 图片
      contentStr += IMAGE_TAG;
    } else {
      contentStr = String(contentStr);
    }
  }

  // return `<span><span>${contentStr}</span></span>`;
  return contentStr;
}

// 表格内容格式化
function tableHtmlFormat(tableObj: any) {
  let tableStr: string = '';
  const tableStyle: string = '';
  for (let i: number = 0; i < tableObj.children.length; i++) {
    // 遍历 tableRow
    const rowObj: any = tableObj.children[i];
    if (rowObj.isHeader) {
      tableStr += '<thead><tr>';
    } else {
      tableStr += '<tbody><tr>';
    }
    for (let j: number = 0; j < rowObj.children.length; j++) {
      // 遍历 tableCell
      const cellObj: any = rowObj.children[j];
      if (rowObj.isHeader) {
        tableStr += `<th style="${tableStyle}">`;
      } else {
        tableStr += `<td>`;
      }
      for (let k: number = 0; k < cellObj.children.length; k++) {
        const contentObj: any = cellObj.children[k];

        let paragraphStr: string = '';
        let alignmentStr: string = '';
        if (contentObj.alignment) {
          alignmentStr = `text-align: ${contentObj.alignment};`;
        } else {
          alignmentStr = 'text-align: left;';
        }
        for (let l: number = 0; l < contentObj.children.length; l++) {
          if (contentObj.children.length > 1 && l === 0 && contentObj.indent && contentObj.indent.firstLine) {
            alignmentStr += 'text-indent: 2em;';
          }
          paragraphStr += paragraphHtmlFormat(contentObj.children[l]);
        }
        tableStr += `<p style="${alignmentStr}">${paragraphStr}</p>`;
      }
      if (rowObj.isHeader) {
        tableStr += '</th>';
      } else {
        tableStr += '</td>';
      }
    }
    if (rowObj.isHeader) {
      tableStr += '</tr></thead>';
    } else {
      tableStr += '</tr></tbody>';
    }
  }
  return `<table style="width: 100%; border-collapse: collapse;">${tableStr}</table>`;
}

// 下载文档
async function downloadDocumentClick() {
  let htmlContentStr: string = ueditor.value.getContent();
  // console.log("htmlContentStr: ", htmlContentStr);

  // htmlContentStr = htmlContentStr.replace(/<img /g, '<img width="650" height="650"');

  const imgSrcReg = /<img[^>]+src=[\\'|\\"]?([^(?"|?'|?>)]+)[\\'|\\"]?[^>]*>/gim;
  const imgSrcList = htmlContentStr.match(imgSrcReg);

  for (let i: number = 0; i < imgSrcList?.length; i++) {
    const imgString: string = imgSrcList[i];

    const imgSrc: string = imgString.match(/src="(.+?)"/)[1];

    /** html转word中的图片尺寸处理 */
    /**
     * 方案一：（图片标签本身要有宽高属性、需要考虑宽高是百分比及auto的情况）
     *
     * 1. 通过图片标签字符转转dom节点获取图片的基本信息；
     * 2. 获取图片的宽高比，然后根据A4纸的尺寸计算出图片应该缩放的比例；
     * 3. 根据比例计算出图片应该缩放后的宽度和高度，并设置给img标签；
     * 4. 将dom节点转换为字符串，替换原html中的img标签；
     */

    /**
     * 方案二：（通用方案）
     *
     * 1. 根据图片的base64字符串获取图片的基本信息；
     * 2. 然后根据A4纸的尺寸计算出图片的缩放尺寸；
     * 3. 创建img标签节点，设置宽高等属性；
     * 4. 使用img标签的innerHTML替换原html中的img标签；
     */

    const info = await getImageInfoFromBase64(imgSrc);
    if (info) {
      // 使用DOM解析器创建一个DOM元素
      // const domParser: any = new DOMParser();
      // const contentDom: any = domParser.parseFromString(imgString, 'text/html');
      // const imgNode: any = contentDom.body.childNodes;
      //
      // const imgWidth: number = imgNode[0].getAttribute('width');
      // const imgHeight: number = imgNode[0].getAttribute('height');

      // A4纸在边距为25mm的情况下，可用区域为453px * 692px
      let newWidth: number = 450;
      let newHeight: number = 690;
      if (info.width > 450 || info.height > 690) {
        if (imgWidth >= imgHeight) {
          const ratio = 690 / imgHeight;
          newWidth = ratio * imgWidth;
        } else {
          const ratio = 450 / imgWidth;
          newHeight = ratio * imgHeight;
        }
      }

      const imgNode: any = document.createElement('span');
      imgNode.setAttribute('src', imgSrc);
      imgNode.setAttribute('width', newWidth);
      imgNode.setAttribute('height', newHeight);
      imgNode.setAttribute('alt', '');

      // const serializer: any = new XMLSerializer();
      // let newHtmlString: string = '';
      // for (let j: number = 0; j < imgNode.length; j++) {
      //   newHtmlString += serializer.serializeToString(imgNode[j]);
      // }

      htmlContentStr = htmlContentStr.replace(imgString, imgNode.innerHTML);
    }
  }

  // 设置表格边框
  const htmlContent = htmlContentStr.replaceAll(/<table/g, `<table border-collapse="collapse" border="1" `);

  const formatContent = `
    	 	<!DOCTYPE html>
    	 	<html lang="en">
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
              <title>${fileName.value}</title>
          </head>
          <body>
             ${htmlContent}
          </body>
        </html>`;

  // const saveParams: any = {
  //   contentList: sliceStringByLength(`<div>${htmlContent}</div>`, 40000)
  // };

  // console.log('内容：', `<div>${htmlContent}</div>`);

  // const { VITE_OTHER_SERVICE_BASE_URL } = import.meta.env;
  // const otherUrl = JSON.parse(VITE_OTHER_SERVICE_BASE_URL);
  //
  // const { data, error } = await htmlToDocAction(saveParams);
  // if (!error) {
  //   saveAs(otherUrl.fileUrl + data, `${fileName.value}.docx`, { encoding: 'UTF-8' });
  //   successMessage('文档下载成功');
  // }

  const convertedFile = htmlDocx.asBlob(formatContent);

  // 生成链接并且下载
  convertedFile.then(fileData => {
    saveAs(fileData as Blob, `${fileName.value}.docx`, { encoding: 'UTF-8' });
    successMessage('文档下载成功');
  });
}

const isOneClickWrite = ref<boolean>(false);

const hTagList: string[] = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'];
const styleList: string[] = [
  'background-color: #fcf2e8; color: #dec3a0;',
  'background-color: #f4e3e0; color: #ae6254;',
  'background-color: #e0e5fb; color: #445fb1;'
];

// 获取文档标签
async function getLabelAction() {
  // let htmlContentStr: string = contentDomOptimize();
  // console.log('htmlContentStr: ', htmlContentStr);

  const contentChildNode: any = contentDomOptimize();

  console.log('contentChildNode: ', contentChildNode);

  const params: any = {
    file_path: '/profile/biaoshu/批量化试验数字管控系统-招标文件.docx'
  };
  const { data, error } = await getDocumentLabelAction(params);
  if (!error) {
    const tableList: any[] = [];
    for (let i: number = 0; i < data.length; i++) {
      const item: any = data[i];
      if (item.type === 2) {
        tableList.push(item);
      }
    }
    console.log('tableList: ', tableList);

    for (let i: number = 0; i < data.length; i++) {
      const item: any = data[i];
      for (let j: number = 0; j < contentChildNode.length; j++) {
        const childNode: any = contentChildNode[j];
        if (childNode.nodeName === 'P' || hTagList.includes(childNode.nodeName)) {
          pLabelNodeContentFormat(item, childNode);
        } else if (childNode.nodeName === 'TABLE') {
          if (childNode.textContent.includes(item.sentence)) {
            for (let k: number = 0; k < childNode.children.length; k++) {
              const tableRow: any = childNode.children[k]; // TBODY
              for (let l: number = 0; l < tableRow.children.length; l++) {
                const tableCell: any = tableRow.children[l]; // TR
                for (let m: number = 0; m < tableCell.children.length; m++) {
                  const tdContent: any = tableCell.children[m]; // TD
                  if (item.sentence === '投标人资质条件、能力、信誉') {
                    debugger;
                  }
                  for (let n: number = 0; n < tdContent.children.length; n++) {
                    const cellContent: any = tdContent.children[n];
                    if (cellContent.nodeName === 'P' || hTagList.includes(cellContent.nodeName)) {
                      pLabelNodeContentFormat(item, cellContent);
                    }
                  }
                }
              }
            }
          }
        }
      }
    }

    const serializer: any = new XMLSerializer();
    let newHtmlString: string = '';
    for (let j: number = 0; j < contentChildNode.length; j++) {
      newHtmlString += serializer.serializeToString(contentChildNode[j]);
    }

    contentHtml.value = newHtmlString;
  }
}

let nodeIndex: number = 0;

// P标签内容优化
function pLabelNodeContentFormat(item: any, childNode: any) {
  if (childNode.textContent.length >= item.sentence.length) {
    if (childNode.textContent.includes(item.sentence)) {
      const labelTextContent: string = childNode.textContent;
      let childNodeStyle: string = '';

      if (childNode && childNode.children && childNode.children.length > 0) {
        if (childNode.children.length === 1) {
          const childrenNodeStyle = childNode.children[0].getAttribute('style');

          childNodeStyle = contentColorHandle(item.color, childrenNodeStyle);

          const startIndex: number = labelTextContent.indexOf(item.sentence);
          const endIndex: number = startIndex + item.sentence.length;

          const startNode: any = document.createElement('span');
          startNode.textContent = labelTextContent.substring(0, startIndex);
          startNode.setAttribute('style', childrenNodeStyle);
          if (startNode.textContent.length > 0) {
            childNode.appendChild(startNode);
          }

          const centerNode: any = document.createElement('span');
          if (childNodeStyle !== '') {
            centerNode.setAttribute('style', childNodeStyle);
          }
          centerNode.textContent = labelTextContent.substring(startIndex, endIndex);
          childNode.appendChild(centerNode);

          const endNode: any = document.createElement('span');
          endNode.textContent = labelTextContent.substring(endIndex);
          endNode.setAttribute('style', childrenNodeStyle);
          if (endNode.textContent.length > 0) {
            childNode.appendChild(endNode);
          }

          childNode.removeChild(childNode.children[0]);
        } else {
          // TODO 增加递归使整个节点内容都被处理
          nodeIndex = 0;
          multiContentNodeFormat(item, childNode, nodeIndex);
        }
      }
    }
  } else if (item.sentence.includes(childNode.textContent)) {
    // const labelTextContent: string = childNode.textContent;
    // if (labelTextContent === '') return;
    // nodeIndex = 0;
    // multiContentNodeFormat(item, childNode, nodeIndex);
  }
}

// 多片段内容处理
function multiContentNodeFormat(item: any, childNode: any, index: number) {
  if (index >= childNode.children.length) return;

  let targetNode: any = null;
  const spanChildNode = childNode.children[index];
  if (spanChildNode.nodeName === 'SPAN') {
    const spanChildText: string = trimPunctuation(spanChildNode.textContent);
    if (item.sentence.length >= spanChildText.length) {
      if (item.sentence.includes(spanChildText)) {
        targetNode = spanChildNode;
      }
    } else if (spanChildText.includes(item.sentence)) {
      targetNode = spanChildNode;
    }

    if (targetNode) {
      const targetText: string = targetNode.textContent;
      const targetNodeStyle: string = targetNode.getAttribute('style');

      const spanNodeStyle: string = contentColorHandle(item.color, targetNodeStyle);

      const targetContentText: string = trimPunctuation(targetText);

      if (item.sentence.length >= targetContentText.length) {
        const centerSpanNode: any = document.createElement('span');
        if (spanNodeStyle !== '') {
          centerSpanNode.setAttribute('style', spanNodeStyle);
        }
        centerSpanNode.textContent = targetText;
        childNode.replaceChild(centerSpanNode, targetNode);
      } else {
        const startIndex: number = targetText.indexOf(item.sentence);
        const endIndex: number = startIndex + item.sentence.length;

        const endSpanNode: any = document.createElement('span');
        endSpanNode.textContent = targetText.substring(endIndex);
        endSpanNode.setAttribute('style', targetNodeStyle);
        if (endSpanNode.textContent.length > 0) {
          childNode.insertBefore(endSpanNode, targetNode);
        }

        const centerSpanNode: any = document.createElement('span');
        if (spanNodeStyle !== '') {
          centerSpanNode.setAttribute('style', spanNodeStyle);
        }
        centerSpanNode.textContent = targetText.substring(startIndex, endIndex);
        if (endSpanNode.textContent.length > 0) {
          childNode.insertBefore(centerSpanNode, endSpanNode);
        } else {
          childNode.insertBefore(centerSpanNode, targetNode);
        }

        const startSpanNode: any = document.createElement('span');
        startSpanNode.textContent = targetText.substring(0, startIndex);
        startSpanNode.setAttribute('style', targetNodeStyle);
        if (startIndex > 0) {
          childNode.insertBefore(startSpanNode, centerSpanNode);
        }

        childNode.removeChild(targetNode);

        // multiContentNodeFormat(item, childNode, nodeIndex);
      }
      nodeIndex += 1;
      multiContentNodeFormat(item, childNode, nodeIndex);
    } else {
      nodeIndex += 1;
      multiContentNodeFormat(item, childNode, nodeIndex);
    }
  } else {
    nodeIndex += 1;
    multiContentNodeFormat(item, childNode, nodeIndex);
  }
}

// 去除字符串中的标点符号
function trimPunctuation(str: string) {
  // 定义要匹配的标点符号集合
  // const punctuation = /[!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/g;

  // 去除开头的标点符号
  // str = str.replace(/^\s*[!"#$%&'()*+,\-.。/:;<=>?@[\\\]^_`{|}~]+/, '');

  // 去除结尾的标点符号
  // str = str.replace(/[!"#$%&'()*+,\-.。/:;<=>?@[\\\]^_`{|}~]+\s*$/, '');

  return str.replace(/^[\p{P}\p{S}\s]+|[\p{P}\p{S}\s]+$/gu, '');
}

// 内容颜色处理
function contentColorHandle(color: number, nodeStyle: string) {
  let spanNodeStyle: string = '';
  switch (color) {
    case 1:
      if (nodeStyle.includes('background-color: #fcf2e8;')) {
        spanNodeStyle = nodeStyle;
      } else {
        spanNodeStyle = `${nodeStyle}background-color: #fcf2e8; color: #dec3a0;`;
      }
      break;
    case 2:
      if (nodeStyle.includes('background-color: #f4e3e0;')) {
        spanNodeStyle = nodeStyle;
      } else {
        spanNodeStyle = `${nodeStyle}background-color: #f4e3e0; color: #ae6254;`;
      }
      break;
    case 3:
      if (nodeStyle.includes('background-color: #e0e5fb;')) {
        spanNodeStyle = nodeStyle;
      } else {
        spanNodeStyle = `${nodeStyle}background-color: #e0e5fb; color: #445fb1;`;
      }
      break;
    default:
      spanNodeStyle = '';
  }
  return spanNodeStyle;
}

// 内容Dom节点优化
function contentDomOptimize() {
  const htmlContentStr: string = ueditor.value.getContent();

  // 使用DOM解析器创建一个DOM元素
  const domParser = new DOMParser();
  const contentDom = domParser.parseFromString(htmlContentStr, 'text/html');
  const contentChildNode = contentDom.body.childNodes;

  for (let i: number = 0; i < contentChildNode.length; i++) {
    const node = contentChildNode[i];
    if (node.nodeName === 'P' || hTagList.includes(node.nodeName)) {
      spanDomOptimize(node);
    } else if (node.nodeName === 'TABLE') {
      // 表格
      const tableNode: any = node;
      const tableChildNode: any = tableNode.childNodes;
      for (let j: number = 0; j < tableChildNode.length; j++) {
        const childNode: any = tableChildNode[j];
        if (childNode.nodeName === 'TR') {
          const trChildNode: any = childNode.childNodes;
          for (let k: number = 0; k < trChildNode.length; k++) {
            const tdNode: any = trChildNode[k];
            if (tdNode.nodeName === 'TD' || tdNode.nodeName === 'TH') {
              const tdChildNode: any = tdNode.childNodes;
              for (let m: number = 0; m < tdChildNode.length; m++) {
                const childNode: any = tdChildNode[m];
                if (childNode.nodeName === 'P' || hTagList.includes(childNode.nodeName)) {
                  spanDomOptimize(childNode);
                }
              }
            }
          }
        }
      }
    }
  }

  return contentChildNode;
}

// Span标签内容优化
function spanDomOptimize(node: any) {
  const textContent: string = node.textContent;
  let childNodeStyle: string = '';
  const childStyle: string[] = [];
  for (let j: number = 0; j < node.children.length; j++) {
    const childNode: any = node.children[j];
    if (childNode.getAttribute('style')) {
      childStyle.push(childNode.getAttribute('style'));
    } else {
      childStyle.push('');
    }
  }
  const newChildStyle: string[] = Array.from(new Set(childStyle));
  if (newChildStyle.length > 0) {
    if (newChildStyle.length === 1) {
      childNodeStyle = newChildStyle[0];

      while (node.firstChild && node.firstChild.nodeName === 'SPAN') {
        node.removeChild(node.firstChild);
      }

      const spanNode: any = document.createElement('span');
      spanNode.setAttribute('style', childNodeStyle);
      spanNode.textContent = textContent;
      node.append(spanNode);
    } else {
      // Warning: 暂不支持多样式合并
    }
  } else {
    while (node.firstChild && node.firstChild.nodeName === 'SPAN') {
      node.removeChild(node.firstChild);
    }

    const spanNode: any = document.createElement('span');
    spanNode.textContent = textContent;
    node.append(spanNode);
  }
}

function searchAndHighlight(content: string, style: string) {
  let span;
  // debugger;
  const range = ueditor.value.selection.getRange();
  const reg = new RegExp(content, 'g'); // 创建正则表达式
  const fragment = ueditor.value.document.createDocumentFragment();
  let node;
  let needParentNode;

  while ((node = fragment.firstChild)) {
    fragment.removeChild(node);
    if (node.nodeType === 3) {
      let match;
      while ((match = reg.exec(node.nodeValue))) {
        needParentNode ||= match[0] !== node.nodeValue;
        if (needParentNode) {
          span = editor.document.createElement('span');
          span.style.cssText = style; // 添加样式
          span.appendChild(node.ownerDocument.createTextNode(match[0]));
          node.parentNode.insertBefore(span, node);
        } else {
          span = editor.document.createElement('span');
          span.style.cssText = style; // 添加样式
          span.appendChild(node.cloneNode(true));
          node.parentNode.insertBefore(span, node);
          node.nodeValue = node.nodeValue.replace(reg, '');
          if (!node.nodeValue.length) {
            node.parentNode.removeChild(node);
          }
        }
        needParentNode = false;
        range.setStart(fragment, 0);
        range.setEnd(fragment, 0);
      }
      if (needParentNode) {
        needParentNode = false;
        range.setStart(fragment, 0).collapse(true);
        range.select();
      }
    }
    if (node) {
      fragment.appendChild(node);
    }
  }
}

const isBack = ref<boolean>(false);

// 返回首页
function backHomeClick() {
  saveContentToService(isOneClickWrite.value ? 0 : 1);
  isBack.value = true;
  if (generateType.value === 0) {
    routerBack();
  } else {
    routerBack();
  }
}

onBeforeRouteLeave((to, from, next) => {
  saveContentToService(isOneClickWrite.value ? 0 : 1);
  isBack.value = true;
  if (isOneClickWrite.value) {
    dialog.warning({
      title: '温馨提示',
      content: `当前内容正在生成中，是否移动到后台继续生成？`,
      positiveText: '确定',
      negativeText: '取消',
      onPositiveClick: () => {
        next(); // 阻止离开
      },
      onNegativeClick: () => {
        next(false);
      }
    });
  } else {
    next(); // 阻止离开
  }
});

// 修改文档标题
function changeDocumentNameClick() {
  openDocNameModal();
}

// 修改文档标题
function renameHandle(projectName: string) {
  fileName.value = projectName;
}

onBeforeUnmount(() => {
  isBack.value = true;
});

onUnmounted(() => {
  setTimeout(() => {
    if (ueditor.value) {
      contentHtml.value = '';
      ueditor.value.destroy();
      ueditor.value = null;
    }
  }, 100);
});
</script>

<template>
  <div class="document-layout min-h-500px flex-col-stretch gap-16px lt-sm:overflow-auto">
    <NSpace vertical>
      <NSpin :show="showLoading" :description="loadingDes" :rotate="false" size="large">
        <template #icon>
          <img src="@/assets/imgs/spin-loading.gif" alt="" width="240" height="240" />
        </template>
        <div v-if="isBack" class="h-full w-full bg-white z-1100"></div>
        <div v-else class="flex-col">
          <div class="content-header">
            <div class="content-left">
              <div class="left-top">
                <span class="name-text">{{ fileName }}</span>
                <img class="name-img" src="@/assets/imgs/icon-name-edit.png" alt="" @click="changeDocumentNameClick" />
                <div v-if="isOneClickWrite" class="status-box">
                  <img class="status-img-gif" src="@/assets/imgs/create-loading.gif" alt="" />
                  <span class="status-text">小主，您的内容正在持续AI生成中，持续时长预计5分钟，请稍后~</span>
                </div>
              </div>
              <div class="right-top">
                <span class="number-text">总章节：{{ Object.keys(catalogMap).length }}</span>
                <!--              <span class="number-text">已完成：8</span>-->
                <span class="number-text">总字数：{{ contentTextLength }}</span>
              </div>
            </div>
            <NSpace>
              <NButton class="write-btn" strong quaternary :disabled="isOneClickWrite" @click="getLabelAction">
                <template #icon>
                  <img src="@/assets/imgs/icon-document-write.png" width="20" alt="" />
                </template>
                获取标签
              </NButton>
            </NSpace>
          </div>
          <div class="flex">
            <div class="catalog">
              <div id="catalog_wrapper">
                <div class="catalog_title_box">
                  <span class="catalog_title">章节名称</span>
                </div>
                <NScrollbar content-class="catalog-list" class="max-h-665px">
                  <div id="catalog_box" class="catalog-list"></div>
                </NScrollbar>
              </div>
            </div>
            <div class="content-box">
              <VueUeditorWrap
                v-model="contentHtml"
                editor-id="document_editor"
                :config="editorConfig"
                :editor-dependencies="editorDependencies"
                @ready="readyHandle"
              />
            </div>
          </div>
        </div>
      </NSpin>
    </NSpace>
    <DocumentName v-model:show="showDocNameModal" :task-id="taskId" :project-name="fileName" @refresh="renameHandle" />
  </div>
</template>

<style>
#catalog_box li {
  color: #333;
  margin: 10px 0 0;
  cursor: pointer;
  word-break: break-all;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
#catalog_box li[type='H1'] {
  font-size: 16px;
  font-weight: bold;
}
#catalog_box li[type='H2'] {
  font-weight: bold;
}
#catalog_box li[type='H2'] span {
  font-size: 14px;
  padding-left: 10px;
}
#catalog_box li[type='H3'] span {
  font-size: 12px;
  padding-left: 20px;
}
#catalog_box li[type='H4'] {
  font-size: 10px;
  padding-left: 30px;
}
#catalog_box li[type='H5'] {
  font-size: 10px;
  padding-left: 40px;
}
#catalog_box li[type='H6'] {
  font-size: 10px;
  padding-left: 50px;
}

.titleItem {
  display: flex;
  flex-direction: row;
  align-items: center;
  cursor: pointer;
}
.statusIcon {
  width: 15px;
  margin-right: 2px;
  height: 15px;
}
.sectionItem {
  height: 20px;
  padding: 4px;
  cursor: pointer;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

.sectionItem span {
  display: inline-block;
}
.itemTitle {
  max-width: 280px;
  word-break: break-all;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
.handleItem {
  display: flex;
  flex-direction: row;
  align-items: center;
  object-fit: contain;
}
.editIcon,
.addIcon,
.writeIcon {
  width: 16px;
  margin: 0 3px;
  height: 16px;
  cursor: pointer;
}
.deleteIcon {
  width: 16px;
  margin-right: 10px;
  margin-left: 3px;
  height: 16px;
  cursor: pointer;
}
</style>

<style scoped lang="scss">
$catalogWidth: 310px;

.bg-layout {
  padding: 16px 16px 0 !important;
  background: url('@/assets/imgs/edit-bg.png');
  background-size: 100% 100%;
}
:deep(.edui-editor) {
  width: auto !important;
}
:deep(.edui-editor-iframeholder) {
  width: auto !important;
}
.document-layout {
}

#catalog_box ul {
  margin: 0px;
  padding: 0px 0px 0px 20px;
}

.catalog {
  width: $catalogWidth;
  height: 720px;
  //margin-right: 4px;
  background: white;
  border-radius: 2px;
  z-index: 900;
}
.content-header {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  background-color: #ffffff;
  height: 92px;
  width: 100%;
  box-shadow: 0px 0px 40px 0px rgba(131, 111, 255, 0.1);
  border-radius: 12px;
  padding: 10px 30px;
  margin-bottom: 8px;
  .content-left {
    display: flex;
    flex-direction: column;
    .left-top {
      display: flex;
      flex-direction: row;
      align-items: center;
      .name-text {
        font-weight: bold;
        font-size: 24px;
        color: #333333;
        line-height: 49px;
      }
      .name-img {
        width: 23px;
        height: 25px;
        margin-left: 15px;
        cursor: pointer;
      }
      .status-box {
        display: flex;
        flex-direction: row;
        align-items: center;
        margin-left: 100px;
        .status-img {
          width: 18px;
          height: 18px;
          margin-right: 5px;
        }
        .status-img-gif {
          width: 32px;
          height: 32px;
          margin-right: 5px;
        }
        .status-text {
          font-size: 16px;
          color: #0d6fb8;
        }
      }
    }
    .right-top {
      display: flex;
      flex-direction: row;
      align-items: center;
      .number-text {
        margin-right: 25px;
        font-weight: 400;
        font-size: 16px;
        color: #666666;
        line-height: 30px;
      }
    }
  }
  .download-btn {
    width: 130px;
    height: 50px;
    background: #ffffff;
    border-radius: 4px;
    border: 1px solid #28da99;
  }
  .write-btn {
    width: 130px;
    height: 50px;
    background: #ffffff;
    border-radius: 4px;
    border: 1px solid #836fff;
  }
  .back-btn {
    width: 80px;
    height: 50px;
    background: #ffffff;
    border-radius: 4px;
    border: 1px solid #ffc367;
  }
}
.content-box {
  width: calc(100% - $catalogWidth);
}

#document_editor {
  width: 100%;
  border: 1px solid #cccccc;
}

#catalog_wrapper {
  padding: 15px 0 15px 7px;
  width: 100%;
}
.catalog_title_box {
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  padding-bottom: 3px;
  border-bottom: 1px dashed #ccc;
  background: #ffffff;
  position: sticky;
  top: 0;
  .catalog_title {
    font-weight: bold;
    font-size: 18px;
    margin-left: 20px;
    line-height: 25px;
  }
  .status_box {
    display: flex;
    flex-direction: row;
    align-items: center;
    margin-left: 8px;
    .status_img {
      width: 12.5px;
      height: 12.5px;
      object-fit: contain;
      margin-right: 2px;
    }
    .complete_text {
      font-weight: 400;
      font-size: 12px;
      color: #68bf7b;
      line-height: 20px;
    }
    .incomplete_text {
      font-weight: 400;
      font-size: 12px;
      color: #c0c0c0;
      line-height: 20px;
    }
  }
}
:deep(.n-spin) {
  width: auto;
  height: auto;
}
.catalog-list {
  list-style: none;
  //height: 705px;
  //overflow-y: auto;
}
</style>
